﻿using System.Linq;
using System.Collections.Generic;
using Red.Controls.ViewModels;
using Red.Core;

namespace Red.Controls.Depot.FileViewItemsProviders
{
    public struct FolderInfo
    {
        /// <summary>
        ///     Name of folder
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        ///     True if folder doesn't correspond to a real on-disk directory
        /// </summary>
        public bool IsFake { get; set; }
    }

    public struct FileInfo
    {
        /// <summary>
        ///     Full local path leading to on-disk file
        /// </summary>
        public string FullPath { get; set; }

        /// <summary>
        ///     Group that file belongs to
        /// </summary>
        public string Group { get; set; }

        /// <summary>
        ///     Should this item be selectable
        /// </summary>
        public bool IsDisabled { get; set; }

        /// <summary>
        ///     A metadata-description displayed in information panel
        /// </summary>
        public string Description { get; set; }

        /// <summary>
        ///     Full path to an on-disk image representing the file's thumbnail
        /// </summary>
        public string FullThumbnailPath { get; set; }
    }

    public abstract class FileViewItemsProvider
    {
        #region Data

        private static List<CommandWrapper> _emptyCommands = new List<CommandWrapper>();

        #endregion Data

        #region Properties
        
        public DepotInfo Depot { get; private set; }

        public string Path { get; private set; }

        /// <summary>
        ///     List of commands displayed for all the items
        /// </summary>
        public virtual IEnumerable<CommandWrapper> Commands { get { return _emptyCommands; } }

        /// <summary>
        ///     If FileView should show items grouped by ItemInfo's group
        /// </summary>
        public virtual bool ShowGroups { get { return false; } }

        /// <summary>
        ///     If the view should re-enumerate items when selection changes (allows to create selection-dependent content)
        /// </summary>
        public virtual bool ReEnumerateOnSelection { get { return false; } }

        #endregion Properties

        #region C-tor

        public FileViewItemsProvider( string path, DepotInfo depot )
        {
            Path = path;
            Depot = depot;
        }

        #endregion C-tor

        #region Public methods

        /// <summary>
        ///     Override this to provide a list of files and folders to be displayed
        /// </summary>
        public abstract void EnumerateItems( IList<FolderInfo> folders, IList<FileInfo> files, IList<FileInfo> selectedFiles );

        /// <summary>
        ///     Adds metadata to the list of directories. Advanced override - the default implementation is sufficient for most cases.
        /// </summary>
        public virtual List<UpdateInfo> ProcessFoldersBatch( IList<FolderInfo> folders, ref int index )
        {
            var result = new List<UpdateInfo>();

            foreach ( FolderInfo folder in folders )
            {
                string path = System.IO.Path.Combine( Path, folder.Name );
                result.Add( new UpdateFolderInfo( index++, path, folder ) );
            }

            return result;
        }

        /// <summary>
        ///     Adds metadata to the list of files. Advanced override - the default implementation is sufficient for most cases.
        /// </summary>
        public virtual List<UpdateFileInfo> ProcessFilesBatch( IList<FileInfo> files, ref int index )
        {
            var result = new List<UpdateFileInfo>();

            IEnumerable<string> filePaths = files.Select( f => f.FullPath );
            var fileMetadata = Depot.SourceControl.GetFileMetaData( filePaths ).ToDictionary( item => item.LocalPath.Path.ToLower() );

            foreach ( FileInfo file in files )
            {
                Perforce.P4.FileMetaData p4Data = null;
                fileMetadata.TryGetValue( file.FullPath.ToLower(), out p4Data );
                result.Add( new UpdateFileInfo( index++, file.FullPath, file, p4Data ) );
            }

            return result;
        }

        #endregion Public methods
    }
}
